package simpleftp.ftp;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * Abstract class to describe commands that have to be implemented
 * in a FTP server and client. 
 * Also implements common attributes and methods.
 */
public abstract class FTPDescriber {
	protected static boolean DEBUG = true;
	protected static String NAME;
	
	protected String 		response, 
							user;
	protected Socket 		connectedSocket;
	
	protected Socket 				socket = null;
	protected BufferedReader 		reader = null;
	protected BufferedWriter 		writer = null;
	protected ObjectInputStream		getDirectory 	= null;
	protected ObjectOutputStream 	sendDirectory 	= null;
	
	/**
     * Sends a raw command to the FTP server.
     */
	protected void sendLine(String line) throws IOException {
		if (socket == null) {
			throw new IOException(NAME + " is not connected.");
		}
		try {
			writer.write(line + "\r\n");
			writer.flush();
			if (DEBUG) {
				System.out.println("> " + line);
			}
		} catch (IOException e) {
			socket = null;
			throw e;
		}
	}
	
	/**
	 * Read a command line from the client
	 * @return The command line
	 */
	protected String readLine() throws IOException {
		String line = reader.readLine();
		if (DEBUG) {
			System.out.println("< " + line);
		}
		return line;
	}

	/**
	 * Get a file from the socket
	 * @param storFile The new file to create locally 
	 * @param sock The socket to use
	 */
	protected void readFile(File storFile, Socket sock) throws IOException {
		transferFile(sock.getInputStream(), new FileOutputStream(storFile));
	}
	
	/**
	 * Send a file through a socket
	 * @param toSend The file to send
	 * @param sock The socket to use
	 */
	protected void sendFile(File toSend, Socket sock) throws IOException {
		transferFile(new FileInputStream(toSend), sock.getOutputStream());		
	}
	
	/**
	 * Get a file from an InputStream and write its content through an OutputStream
	 * @param is The stream to read from
	 * @param os The stream to write on
	 */
	private void transferFile(InputStream is, OutputStream os) throws IOException {
		byte[] buffer = new byte[4096];
        int bytesRead = 0;
        while ((bytesRead = is.read(buffer)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        os.flush();
        os.close();
        is.close();
	}
	
	public abstract String pwd() throws IOException;
	
	public abstract boolean stor(File file) throws IOException;
	
	public abstract boolean retr(File directory, String path) throws IOException;
	
	public abstract String ls(boolean useJson) throws IOException;
	
	public abstract boolean cwd(String path) throws IOException;
	
	protected abstract void pasv() throws IOException;
	
}
